package edu.iscas.appcheckclient.service;

import android.util.Log;
import android.view.accessibility.AccessibilityNodeInfo;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;


public class WindowIdManager {

    private static final String TAG = WindowIdManager.class.getSimpleName();

    private RecordService recordService;

    //保存windowId
    private List<Integer> windowIdList = new ArrayList<>(10);
    //对应windowId出现的次数？Map的key是resourceName，value是出现次数，list的索引对应上一个列表的索引
    private List<Map<String, Integer>> resourceNameCountMapList = new ArrayList<>(10);
    //对应windowId的AccessibilityNodeInfo?
    private List<List<AccessibilityNodeInfo>> nodeInfoList = new ArrayList<>(10);

    private StringAndSelector focusedNode;

    public WindowIdManager(RecordService recordService) {
        super();
        this.recordService = recordService;
    }

    public Integer getResourceNameCount(int paramInt, String paramString)
    {
        if (this.windowIdList.contains(Integer.valueOf(paramInt)))
        {
            paramInt = this.windowIdList.indexOf(paramInt);
            Integer idCount = (Integer)((Map)this.resourceNameCountMapList.get(paramInt)).get(paramString);
            if (idCount == null) {
                Log.e(TAG, "getIdCount:count not found");
                idCount = 0;
            }
            return idCount;
        }
        Log.e(TAG, "getIdCount:windowId not found");
        return 0;
    }

    /**
     * Get the AccessibilityNodeInfo list of the parameter windowId
     * @param windowId
     * @return return a list with length of 0 if the parameter windowId is not saved
     */
    public List<AccessibilityNodeInfo> getNodeInfoList(int windowId){
        List<AccessibilityNodeInfo> nodeInfoList = new ArrayList<>();
        if(this.windowIdList.contains(Integer.valueOf(windowId))){
            int index = this.windowIdList.indexOf(windowId);
            nodeInfoList = (List)this.nodeInfoList.get(index);
        }
        return nodeInfoList;
    }

    /**
     * Add the String-int pair of the param node info and its children to the map and
     * the AccessibilityNodeInfo to the list using BFS search
     * @param nodeInfo
     * @param list
     * @return
     */
    private Map<String, Integer> buildMap(AccessibilityNodeInfo nodeInfo, ArrayList<AccessibilityNodeInfo> list){
        HashMap hashMap = new HashMap();
        if(nodeInfo != null){
            //作为bfs的队列使用
            ArrayList queue = new ArrayList();
            queue.add(nodeInfo);
            while(!queue.isEmpty()){
                nodeInfo = (AccessibilityNodeInfo)queue.remove(0);
                list.add(nodeInfo);
                String resourceName = nodeInfo.getViewIdResourceName();
                Integer count;
                if(resourceName != null){
                    count = (Integer)hashMap.get(resourceName);
                    if(count != null)
                        hashMap.put(resourceName, count + 1);
                    else
                        hashMap.put(resourceName, 1);
                }
                int i = 0;
                while (i < nodeInfo.getChildCount()){
                    AccessibilityNodeInfo child = nodeInfo.getChild(i);
                    if(child != null) {
                        queue.add(child);
                    }
                    i += 1;
                }
            }
        }
        return hashMap;
    }

    public void insertUpdateWindow(){
        AccessibilityNodeInfo rootNodeInfo = this.recordService.getRootInActiveWindow();
        if(rootNodeInfo != null){
            int rootWindowId = rootNodeInfo.getWindowId();
            int index;
            //如果保存了这个windowId，则清空所有和他有关的信息
            if(this.windowIdList.contains(Integer.valueOf(rootWindowId))) {
                index = this.windowIdList.indexOf(rootWindowId);
                this.windowIdList.remove(index);
                this.nodeInfoList.remove(index);
                this.resourceNameCountMapList.remove(index);
            }else {
                //如果没有，且长度大于10，要清除最后的windowId
                if(this.resourceNameCountMapList.size() >= 10){
                    this.windowIdList.remove(9);
                    this.resourceNameCountMapList.remove(9);
                    this.nodeInfoList.remove(9);
                }
            }
            //新建所有和这个windowId有关的信息
            ArrayList<AccessibilityNodeInfo> list = new ArrayList<>();
            this.windowIdList.add(0, rootWindowId);
            this.resourceNameCountMapList.add(0, buildMap(rootNodeInfo,list));
            //执行buildMap之后，list中包含这个根节点和他的所有子节点的nodeinfo
            this.nodeInfoList.add(0, list);

            Iterator<AccessibilityNodeInfo> iter = list.iterator();
            int i = 0;
            while(iter.hasNext()){
                AccessibilityNodeInfo nodeInfo = iter.next();
                if(nodeInfo != null){
                    if(nodeInfo.isFocused()){
                        if(i != 0){
                            Log.d(TAG, "found last on focus node twice");
                        }
                        i = 1;
                        this.focusedNode = new StringAndSelector(nodeInfo.getClassName().toString(),
                                RecordService.createSelector(this.recordService, nodeInfo));
                    }
                }
            }
        }else{
            Log.e(TAG, "update: getRootInActiveWindow is null");
        }
    }


    /**
     * check if the given ContentDescription can used to match the unique view.
     * @param windowId
     * @param paramContentDescription
     * @return
     */
    public boolean canMatchByContentDescription(int windowId, String paramContentDescription){
        int i;
        if(this.windowIdList.contains(Integer.valueOf(windowId))){
            Iterator<AccessibilityNodeInfo> iter = getNodeInfoList(windowId).iterator();
            i = 0;
            while(iter.hasNext()){
                AccessibilityNodeInfo nodeInfo = iter.next();
                if(nodeInfo.getContentDescription() != null){
                    if(nodeInfo.getContentDescription().toString().equals(paramContentDescription)) {
                        i += 1;
                        if(i > 1)return false;
                    }
                }
            }
            //i==1 表示可以通过ContentDescription找到唯一view
            return i == 1;
        }
        return false;
    }

    public boolean canMatchByText(int windowId, String paramString){
        int i;
        if(this.windowIdList.contains(Integer.valueOf(windowId))){
            Iterator<AccessibilityNodeInfo> iter = getNodeInfoList(windowId).iterator();
            i = 0;
            while(iter.hasNext()){
                AccessibilityNodeInfo nodeInfo = iter.next();
                if(nodeInfo.getText() != null){
                    if(nodeInfo.getText().toString().equals(paramString)){
                        i += 1;
                        if(i > 1)return false;
                    }
                }
            }
            return i == 1;
        }
        return false;
    }

    public boolean canMatchByHint(int windowId, String paramText){
        int i;
        if(this.windowIdList.contains(Integer.valueOf(windowId))){
            Iterator<AccessibilityNodeInfo> iter = getNodeInfoList(windowId).iterator();
            i = 0;
            while(iter.hasNext()){
                AccessibilityNodeInfo nodeInfo = iter.next();
                if (recordService.canGetHint(nodeInfo)) {
                    if (nodeInfo.getText().toString().equals(paramText)) {
                        i += 1;
                        if(i > 1)return false;
                    }
                }
            }
            return i == 1;
        }
        return false;
    }
}
